﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Abp;
using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.AutoMapper;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.EntityFrameworkCore.Repositories;
using Abp.Extensions;
using AbpDemo.Domain.Orders;
using AbpDemo.Goods;
using AbpDemo.Orders.Dto;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace AbpDemo.Orders
{
    public class OrderAppService : AsyncCrudAppService<Order_1, OrderDto, Guid, OrderQueryInput, PlaceOrderInput>
    {
        private readonly IGoodsAppService _goodsService;

        public OrderAppService(IRepository<Order_1, Guid> repository,
            IGoodsAppService goodsService) : base(repository)
        {
            _goodsService = goodsService;
            
        }
      

        #region override CRUD


        public override Task<PagedResultDto<OrderDto>> GetAll(OrderQueryInput input)
        {
            return base.GetAll(input);
        }

        public override Task<OrderDto> Get(EntityDto<Guid> input)
        {
            return base.Get(input);
        }

        /// <summary>
        /// 下订单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public override async Task<OrderDto> Create(PlaceOrderInput input)
        {
            var goods = await _goodsService.GetById(input.GoodsId);
            if (goods == null)
            {
                throw new ArgumentNullException(nameof(input.GoodsId));
            }

            Order_1 order = Order_1.CreateInstance();
            order.PlaceOrder(goods, input.Amount);
            await Repository.InsertAsync(order);
            await CurrentUnitOfWork.SaveChangesAsync();

            return order.MapTo<OrderDto>();
            //return MapToEntityDto(order);
        }

        /// <summary>
        /// 修改或追加订单
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [HttpPost]
        public override async Task<OrderDto> Update(PlaceOrderInput input)
        {
            var order = await Repository.GetAll().Include(i => i.Items).ThenInclude(g => g.Goods)
                .FirstOrDefaultAsync(o => o.Id == input.Id);
            if (order == null)
            {
                throw new ArgumentNullException(nameof(input.Id));
            }

            var goods = await _goodsService.GetById(input.GoodsId);
            if (goods == null)
            {
                throw new ArgumentNullException(nameof(input.GoodsId));
            }

            order.AttachItems(goods, input.Amount);
            await CurrentUnitOfWork.SaveChangesAsync();
            return order.MapTo<OrderDto>();
        }

        [HttpPost]
        public override Task Delete(EntityDto<Guid> input)
        {
            return base.Delete(input);
        }

        protected override IQueryable<Order_1> CreateFilteredQuery(OrderQueryInput input)
        {
            var query = Repository.GetAll();
            if (!input.OrderNo.IsNullOrWhiteSpace())
            {
                query = query.Where(o => o.OrderNo.Contains(input.OrderNo.Trim()));
            }

            return query;
        }

        protected override async Task<Order_1> GetEntityByIdAsync(Guid id)
        {
            var order = await Repository.GetDbContext().Set<Order_1>().Include(o => o.Items).ThenInclude(o => o.Goods)

                .FirstOrDefaultAsync(o => o.Id == id);
            return order;
        }

        protected override IQueryable<Order_1> ApplyPaging(IQueryable<Order_1> query, OrderQueryInput input)
        {
            input.MaxResultCount = input.MaxResultCount == 0 ? 10 : input.MaxResultCount;
            return base.ApplyPaging(query, input);
        }

        protected override IQueryable<Order_1> ApplySorting(IQueryable<Order_1> query, OrderQueryInput input)
        {
            if (input.Sorting.IsNullOrEmpty())
            {
                return query.OrderByDescending(o => o.OrderNo);
            }
            else
            {
                return base.ApplySorting(query, input);
            }
        }

        #endregion
    }
}